<?php

namespace App\Kuafu\CustomerCoupon\Service;

use App\Exceptions\BaseException;
use App\Kuafu\Activity\Enum\ActivityCodeEnum;
use App\Kuafu\Activity\Enum\ActivityEnum;
use App\Kuafu\Activity\Model\ActivityModel;
use App\Kuafu\Activity\Service\ActivityService;
use App\Kuafu\Base\Enum\BaseCodeEnum;
use App\Kuafu\Base\Enum\ClientEnum;
use App\Kuafu\Base\Model\BaseModel;
use App\Kuafu\Base\Service\BaseService;
use App\Kuafu\Common\Service\CommonService;
use App\Kuafu\Coupon\Enum\CouponEnum;
use App\Kuafu\CouponExt\Channel\CouponExtBase;
use App\Kuafu\CouponExt\Enum\CouponExtCodeEnum;
use App\Kuafu\CouponExt\Enum\CouponExtEnum;
use App\Kuafu\CouponExt\Exceptions\CouponExtException;
use App\Kuafu\CouponPackage\Enum\CouponPackageEnum;
use App\Kuafu\CouponPackage\Service\CouponPackageService;
use App\Kuafu\Customer\Enum\CustomerCodeEnum;
use App\Kuafu\Customer\Enum\PlatformCodeEnum;
use App\Kuafu\Customer\Model\CustomerActionLogModel;
use App\Kuafu\Customer\Model\CustomerModel;
use App\Kuafu\Customer\Model\CustomerPlatformModel;
use App\Kuafu\Customer\Service\CustomerActionLogService;
use App\Kuafu\Customer\Service\CustomerSendCouponLogService;
use App\Kuafu\CustomerCoupon\Convert\CustomerCouponConvent;
use App\Kuafu\CustomerCoupon\Enum\CodeEnum;
use App\Kuafu\CustomerCoupon\Enum\CustomerCouponCacheEnum;
use App\Kuafu\CustomerCoupon\Enum\CustomerCouponCodeEnum;
use App\Kuafu\CustomerCoupon\Exceptions\CustomerCouponException;
use App\Kuafu\CustomerCoupon\Jobs\CustomerCouponExpireNotice;
use App\Kuafu\CustomerCoupon\Jobs\ReceiveCouponJob;
use App\Kuafu\CustomerCoupon\Model\CustomerCouponModel;
use App\Kuafu\CustomerCoupon\Model\CustomerCouponShopMappingModel;
use App\Kuafu\CustomerCoupon\Model\CustomerCouponUseHistoryModel;
use App\Kuafu\CustomerCoupon\Model\CustomerSendCouponLogModel;
use App\Kuafu\CustomerCoupon\Model\SendCustomerCouponFailLog;
use App\Kuafu\CustomerCoupon\Resources\CustomCouponListResource;
use App\Kuafu\CustomerCoupon\Resources\CustomCouponUseHistoryListResource;
use App\Kuafu\CustomerCoupon\Resources\CustomerCouponDetailResource;
use App\Kuafu\CustomerCoupon\Resources\MerchantCustomCouponUsedListResource;
use App\Kuafu\Order\Model\OrderExternalSplitModel;
use App\Kuafu\Order\Service\OrderCouponExternalService;
use App\Kuafu\Order\Service\OrderPlacingService;
use App\Kuafu\Product\Model\Product;
use App\Kuafu\Product\Service\ProductService;
use App\Kuafu\Product\Service\ProductShopService;
use App\Kuafu\Shop\Model\Shop;
use App\Kuafu\Shop\Service\DouyinSelfLibrary\DouyinSelfService;
use App\Kuafu\Shop\Service\ShopService;
use App\Kuafu\User\Service\AuthService;
use App\Kuafu\Wechat\Service\WechatConfigService;
use App\Library\FeiShu\SendFs;
use Doctrine\DBAL\Query\QueryBuilder;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Psr\SimpleCache\InvalidArgumentException;
use function Sodium\compare;

class CustomerCouponService extends BaseService
{


    /**
     * 券到账｜到期提醒
     *
     * @param $userId
     * @param Collection $collection
     * @param $shopId
     */
    public static function dispatchCouponMsg($userId, Collection $collection, $shopId)
    {
        try {
            $couponLists = $collection->map(function ($v) {
                if ($v->isExpireNotice == CodeEnum::EXPIRE_NOTICE_YES || $v->isArrivalNotice == CodeEnum::ARRIVAL_NOTICE_YES) {
                    $noticeTime          = $v->endAt - (24 * 60 * 60 * $v->expireNoticeDay);
                    $v->noticeTime       = $noticeTime;
                    $v->noticeDate       = date('Y-m-d', $noticeTime);
                    $v->noticeFormatTime = strtotime(date('Y-m-d', $noticeTime) . ' 17:00:00');
                    return $v;
                }
            })->filter()->values();

            //券到期提醒
            $couponLists->where('isExpireNotice', '=', CodeEnum::EXPIRE_NOTICE_YES)->groupBy('noticeDate')
                        ->each(function (
                            Collection $v
                        ) use ($userId, $shopId) {
                            $nearCoupon = $v->where('noticeFormatTime', '>', time())->sortBy('endAt')->first();
                            if ($nearCoupon) {
                                CustomerCouponExpireNotice::dispatch(
                                    $userId,
                                    $nearCoupon->name,
                                    $nearCoupon->startAt,
                                    $nearCoupon->endAt,
                                    vsprintf("您有%d张优惠券即将到期，请尽快使用", [$v->count()]),
                                    $shopId
                                )->onQueue(CustomerCouponExpireNotice::QUEUE_NAME)
                                                          ->delay($nearCoupon->noticeFormatTime - time());
                            }
                        });

            //券到账提醒
//            $arrivalNoticeCount = $couponLists->where('isArrivalNotice', '=', CodeEnum::ARRIVAL_NOTICE_YES)->count();
//            if ($arrivalNoticeCount > 0) {
//                CustomerCouponArrivalNotice::dispatch(
//                    $userId,
//                    $couponLists->where('isArrivalNotice', '=', CodeEnum::ARRIVAL_NOTICE_YES)->getIterator()
//                                ->current()->name,
//                    $couponLists->where('isArrivalNotice', '=', CodeEnum::ARRIVAL_NOTICE_YES)->sortBy('startAt')
//                                ->first()->startAt,
//                    $couponLists->where('isArrivalNotice', '=', CodeEnum::ARRIVAL_NOTICE_YES)->sortByDesc('startAt')
//                                ->first()->endAt,
//                    vsprintf("您有%d张优惠券到账了，请尽快使用", [$arrivalNoticeCount])
//                )->onQueue(CustomerCouponArrivalNotice::QUEUE_NAME);
//            }
        } catch (\Exception $exception) {
            Log::channel('wechat')->info('优惠券过期/到账提醒加入job失败', ['userId' => $userId]);
            return;
        }

    }


    /**
     * 发放优惠券
     * @param $userId
     * @param $activityId
     * @param $activityType
     * @param int $shopId
     * @return array
     * @throws CustomerCouponException
     * @throws InvalidArgumentException
     */
    public static function sendCoupon($userId, $activityId, $activityType, int $shopId = 0): array
    {
        $uuid = md5(microtime(true) . rand(1, 10000));
        Log::info("{$uuid}-发放优惠券进入-$userId",
            ['活动id' => $activityId, '用户id' => $userId, '店铺id' => $shopId]);
        //根据活动id查询活动信息
        $activityByIdDetail = Cache::remember(CustomerCouponCacheEnum::getBandMobileActivityInfo($activityId),
            CustomerCouponCacheEnum::BAND_ACTIVITY_INFO_TIME,
            function () use ($activityId) {
                return ActivityService::getActivityInfoById($activityId);
            });
        //活动基本信息
        $activityBasis = $activityByIdDetail['basis'];
        //活动关联优惠券信息
        $couponInfo = $activityByIdDetail['coupons'];
        if (!empty($activityBasis) || empty($couponInfo)) {
            //活动店铺信息
            $shopInfo  = $activityByIdDetail['shopIds'];
            $couponArr = [];
            try {
                DB::beginTransaction();
                $insertCouponCollection = new Collection();
                $userCouponIds          = [];
                foreach ($couponInfo as $coupon) {
                    for ($i = 1; $i <= $coupon->number; $i++) {
                        $couponArr['userId']         = $userId;
                        $couponArr['activityId']     = $activityId;
                        $couponArr['source']         = CustomerCouponModel::SOURCE_ACTIVITY;
                        $couponArr['sourceName']     = $activityBasis["name"] ?? "";
                        $couponArr['activityName']   = $activityBasis["name"] ?? "";
                        $couponArr['activityType']   = $activityBasis["type"] ?? 0;
                        $couponArr['couponId']       = $coupon->couponId;
                        $couponArr['couponCode']     = self::generateUserCouponCode(CodeEnum::COUPON_CODE_LENGTH);
                        $couponArr['name']           = $coupon->name;
                        $couponArr['desc']           = $coupon->desc;
                        $couponArr['couponType']     = $coupon->type;
                        $couponArr['useTimeType']    = $coupon->useTimeType;
                        $couponArr['canUseProduct']  = $coupon->canUseProduct;
                        $couponArr['productUseType'] = $coupon->productUseType;
                        $couponArr['shopType']       = $activityBasis['shopType'];
                        $couponArr['discount']       = $coupon->discount;
                        $couponArr['couponImg']      = $coupon->couponImg;
                        if ($coupon->useTimeType == CodeEnum::USE_TIME_TYPE_FIXED) {
                            //如果等于1 表示固定时间
                            $couponArr['startAt'] = $coupon->startAt;
                            $couponArr['endAt']   = $coupon->endAt;
                        } else {
                            //如果等于2 表示 领取后几天生效 有效期是几天
                            $startTime            = time() + $coupon->startAt * CodeEnum::COUPON_DAY_TIME;
                            $year                 = date("Y", $startTime);
                            $month                = date("m", $startTime);
                            $day                  = date("d", $startTime) + $coupon->endAt;
                            $endTime              = mktime(23, 59, 59, $month, $day, $year);//当天结束时间戳
                            $couponArr['startAt'] = $startTime;
                            $couponArr['endAt']   = $endTime;
                        }
                        $couponArr['useCondition']        = $coupon->useCondition;
                        $couponArr['useMax']              = $coupon->useMax;
                        $couponArr['costPrice']           = $coupon->costPrice;
                        $couponArr['availableSource']     = $coupon->availableSource;
                        $couponArr['isSuperposeCoupon']   = $coupon->isSuperposeCoupon;
                        $couponArr['isSuperposeActivity'] = $coupon->isSuperposeActivity;
                        $couponArr['unableDate']          = $coupon->unableDate;
                        $couponArr['unableTime']          = $coupon->unableTime;
                        $couponArr['isWechatNotice']      = $activityBasis['isWechatNotify'];
                        $couponArr['isSmsNotice']         = $activityBasis['isSmsNotify'];
                        $couponArr['notifyAheadDays']     = $activityBasis['notifyAheadDays'];
                        $couponArr['cappedAmount']        = $coupon->cappedAmount;
                        $couponArr['isExpireNotice']      = $coupon->isExpireNotice;
                        $couponArr['isArrivalNotice']     = $coupon->isArrivalNotice;
                        $couponArr['expireNoticeDay']     = $coupon->expireNoticeDay;
                        $couponArr['createdAt']           = time();
                        Log::info("{$uuid}-绑定手机号发放优惠券：优惠券信息", $couponArr);
                        //优惠券信息入库
                        $customerCouponId = CustomerCouponModel::insertData($couponArr);
                        $insertCouponCollection->push((object)[
                            'name'            => $couponArr['name'],
                            'startAt'         => $couponArr['startAt'],
                            'endAt'           => $couponArr['endAt'],
                            'isExpireNotice'  => $couponArr['isExpireNotice'],
                            'isArrivalNotice' => $couponArr['isArrivalNotice'],
                            'expireNoticeDay' => $couponArr['expireNoticeDay']
                        ]);
                        array_push($userCouponIds, $customerCouponId);

                        $customerCouponIdArr = ['customerCouponId' => $customerCouponId];

                        //如果是活动门店是部分门店，则需要加入关联表，其他不加入
                        if ($activityBasis['shopType'] == CodeEnum::COUPON_SHOP_TYPE_PART) {
                            array_walk($shopInfo, function (&$value, $key, $customerCouponIdArr) {
                                $value = array_merge($value, $customerCouponIdArr);
                            }, $customerCouponIdArr);
                            //绑定用户优惠券店铺
                            Log::info("{$uuid}-绑定手机号发放优惠券：店铺信息", $shopInfo);
                            CustomerCouponShopMappingModel::addData($shopInfo);
                        } else {
                            CustomerCouponShopMappingModel::addData(['shopId' => 0, 'customerCouponId' => $customerCouponId, 'createdAt' => time()]);
                        }
                    }
                }
                //记录发放日志
                $data = [
                    'userId'       => $userId,
                    'shopId'       => $shopId,
                    'activityId'   => $activityId,
                    'activityType' => $activityType,
                    'createdAt'    => time(),
                    'updatedAt'    => time(),
                ];
                CustomerSendCouponLogService::addData($data);

                //活动参与人数更新
                ActivityModel::query()->where("id", $activityId)->increment("hasJoinNum");

                DB::commit();
                //优惠券到账&到期提醒
                self::dispatchCouponMsg($userId, $insertCouponCollection, $shopId);
                // 【 队列入队 】【 领取优惠券 】
                try {
                    foreach ($userCouponIds as $k => $userCouponIdSingle) {
                        ReceiveCouponJob::dispatch(
                            $shopId,
                            $activityId,
                            ReceiveCouponJob::TYPE_ACTIVITY,
                            '',
                            vsprintf('[ %s ] - [ %s ] - [ %s ]', [
                                '店内活动',
                                '活动',
                                $activityBasis['name']
                            ]),
                            $userCouponIdSingle,
                            $k == 0 ? $userCouponIds : []
                        )->onQueue(ReceiveCouponJob::$QUEUE_NAME);
                    }
                } catch (\Exception $e) {
                    CommonService::fsLogException(
                        '【 队列入队 】【 领取优惠券 】', $e,
                        [
                            'shopId'   => $shopId,
                            'source'   => '【 活动 】- ' . $activityBasis['name'],
                            'couponId' => $userCouponIdSingle
                        ], true);
                }

                Log::info("{$uuid}-绑定手机号发放优惠券：成功", ['userId' => $userId, 'activityId' => $activityId]);

                return $userCouponIds;
            } catch (\Exception $exception) {
                DB::rollBack();
                Log::info("{$uuid}-绑定手机号发放优惠券：失败",
                    ['userId' => $userId, 'activityId' => $activityId, 'msg' => $exception->getMessage()]);
                SendFs::newRobot()->setTitleContent('绑定手机号送券发放失败',
                    "userId:{$userId}---activityId:{$activityId}---message：{$exception->getMessage()}")->send();
                throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_CUSTOMER_COUPON_RECEIVED_FAIL);
            }
        } else {
            Log::info("{$uuid}-绑定手机号发放优惠券：失败", [
                'userId'     => $userId,
                'activityId' => $activityId,
                'msg'        => CustomerCouponCodeEnum::ERR_CUSTOMERCOUPON_ID_NOT_EXIST
            ]);
            SendFs::newRobot()->setTitleContent('绑定手机号送券发放失败',
                "userId:{$userId}---activityId:{$activityId}---message：{活动信息不存在或者活动优惠券信息不存在}")
                  ->send();
            throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_CUSTOMER_COUPON_RECEIVED_FAIL);
        }
    }

    /**
     * 更改用户优惠券状态
     * @param $couponId
     * @param $status
     */
    public static function setCouponStatus($couponId, $status)
    {
        CustomerCouponModel::setStatus($couponId, $status);
    }

    /**
     * 获取订单可用优惠券列表
     * @param $userId
     * @param $status
     * @param $pageNum
     * @param $pageSize
     * @return array
     */
    public static function getUserCouponList($userId, $status, $pageNum, $pageSize, $couponType, $availableSource, $shopId, $searchShopId, $brandId, $isGetNowCoupon): array
    {
        if ($status == 0) {
            $customerCouponList = CustomerCouponModel::getUserCouponList($userId, $couponType, $availableSource, $searchShopId, $isGetNowCoupon);
            $dataList = $customerCouponList;
            $res = [
                'pageNum'  => 1,
                'pageSize' => count($customerCouponList),
                'count'    => count($customerCouponList),
            ];

        } else {
            $customerCouponList = CustomerCouponModel::getUserHistoryCouponList($userId, $pageNum, $pageSize, $couponType, $availableSource, $searchShopId);
            $dataList = collect($customerCouponList->items());
            $res = [
                'pageNum'  => $customerCouponList->currentPage(),
                'pageSize' => $customerCouponList->perPage(),
                'count'    => $customerCouponList->total(),
            ];
        }


        // 过滤店铺 注意条件
        $lists = $dataList->map(function ($item) use ($searchShopId)  {
            // 仅部分门店时候过滤
            if (count($item->couponShopRel) == 0 && $searchShopId > 0 &&  $item->shopType == CodeEnum::COUPON_SHOP_TYPE_PART){
                return null;
            }
            return $item;
        })->filter()->toArray();

        // 商品券追加商品信息
        if (!empty($lists)) {
            // 商品数据 : 跟菜单保持一致
            $ps                   = new ProductShopService($brandId, $shopId);
            $shopProductListMerge = $ps->getShopProductList();

            foreach ($lists as $k => $value) {
                $productInfo = [];
                if ($value['couponType'] == CodeEnum::COUPON_TYPE_EXCHANGE && !empty($value['canUseProduct'])) {
                    // 兼容数据，取第一个
                    $ids         = explode(',', $value['canUseProduct']);
                    $productInfo = $ps->getShopProductInfo($shopProductListMerge, $ids[0], ClientEnum::QUERY_CLIENT_TYPE_ALL);
                }
                $lists[$k]['productInfo'] = $productInfo;
            }
        }
        $res['list'] = array_values($lists);
        return CustomerCouponConvent::customerCouponListConvent($res);
    }

    /**
     * 生成用户唯一优惠券编码
     * @return string
     * @throws InvalidArgumentException
     */
    public static function generateUserCouponCode(): string
    {
        $key    = "COUPON_CODE_PREFIX";
        $redis  = Cache::store("redis");
        $prefix = $redis->get($key);
        if (!$prefix) {
            $prefix = 1000000000;
            $redis->set($key, $prefix);
        } else {
            $prefix = $redis->increment($key, random_int(1, 9));
        }
        return vsprintf("%d%d", [$prefix, random_int(1000, 9999)]);
    }

    public static function getFailList()
    {
        return SendCustomerCouponFailLog::getFailList(100, 1, 1);
    }

    /**
     * @param $brandId
     * @param $shopId
     * @param $userId
     * @param $productList
     * @param $usedCouponList
     * @param $Source
     * @param bool $withExchangeCoupon
     * @return CustomerEnableCouponService
     */
    public static function getUserCanUseCouponList(
        $brandId,
        $shopId,
        $userId,
        $productList,
        $usedCouponList,
        $Source,
        bool $withExchangeCoupon = true
    ): CustomerEnableCouponService {
        $productListCollection = collect($productList);
        // todo 查询传递过来的优惠券信息
        $couponCodes    = array_column($usedCouponList, 'couponCode');
        $usedCouponList = CustomerCouponModel::getCouponListByCodeList(
            $userId, $couponCodes, $shopId
        )->when(
            !$withExchangeCoupon,
            function ($query) {
                return $query->where("couponType", "<>", CouponEnum::COUPON_TYPE_EXCHANGE);
            }
        )->map(
            function (CustomerCouponModel $customerCouponModel) use (
                $productListCollection
            ) {
                // todo 存在商品券 则用商品最新价格覆盖折扣金额
                if (
                    $customerCouponModel->couponType == CouponEnum::COUPON_TYPE_EXCHANGE
                    &&
                    $product = $productListCollection->where("productId", $customerCouponModel->canUseProduct)
                                                     ->first()
                ) {
                    $customerCouponModel->discount = $product["price"];
                }

                // todo 获取菜品图片
                if (
                    $customerCouponModel->couponType == CodeEnum::COUPON_TYPE_EXCHANGE
                    &&
                    $customerCouponModel->productRel
                ) {
                    $customerCouponModel->productRel->imageUrl = picturePath($customerCouponModel->productRel->imageUrl);
                }
                return $customerCouponModel;
            })->values()->toArray();

        $canUseCouponService = new CustomerEnableCouponService($brandId, $shopId, $userId, $productList,
            $usedCouponList, $Source);
        return $canUseCouponService->initCustomerCoupon()
                                   ->filterCustomerCoupon();
    }

    //根据优惠券ID获取列表
    public static function getCustomerCouponList(
        $couponId,
        $phone,
        $status,
        $couponCode,
        $startTime,
        $endTime,
        $pageSize,
        $pageNum
    ): array {
        // 如果是用户名  获取用户ID
        $customerIdByPhone = '';
        if ($phone) {
            $customerIdByPhone = CustomerModel::query()
                                              ->where('mobile', '=', $phone)
                                              ->pluck('id')
                                              ->toArray();
            $customerIdByPhone = $customerIdByPhone ? $customerIdByPhone[0] : '';
        }
        //优惠券已使用与未使用统计
        $useCount   = [];
        $noUseCount = [];
        $count      = CustomerCouponModel::query()
                                         ->where('couponId', '=', $couponId)
                                         ->get()
                                         ->toArray();
        if (!empty($count)) {
            foreach ($count as $item) {
                if ($item['status'] == CodeEnum::COUPON_STATUS_USED) {
                    $useCount[] = $item;
                } elseif ($item['status'] == CodeEnum::COUPON_STATUS_NO_USED) {
                    $noUseCount[] = $item;
                }
            }
        }
        $list           = CustomerCouponModel::query()
                                             ->where('couponId', '=', $couponId)
                                             ->when($phone, function ($query) use ($customerIdByPhone) {
                                                 $query->where('userId', '=', $customerIdByPhone);
                                             })
                                             ->when(strlen($status), function ($query) use ($status) {
                                                 $query->where('status', '=', $status);
                                             })
                                             ->when($couponCode, function ($query) use ($couponCode) {
                                                 $query->where('couponCode', '=', $couponCode);
                                             })
                                             ->when($startTime && $endTime,
                                                 function ($query) use ($startTime, $endTime) {
                                                     $query->whereBetween('createdAt',
                                                         [strtotime($startTime), strtotime($endTime)]);
                                                 })
                                             ->with(['customers', 'orderRel', 'shopRel'])
                                             ->orderByDesc('id')
                                             ->paginate($pageSize, ['*'], 'page', $pageNum);
        $coupon['data'] = $list->toArray();
        foreach ($coupon['data']['data'] as $k => $item) {
            if ($item['shop_rel'] != null) {
                $coupon['data']['data'][$k]['shop'] = Shop::getShopById($item['shop_rel']['shopId']);
            }
        }
        $coupon['useCount']   = count($useCount);
        $coupon['noUseCount'] = count($noUseCount);
        //优惠券累计金额统计
        $coupon['amount'] = 0;
        foreach ($coupon['data']['data'] as $item) {
            if (!empty($item['order'])) {
                $coupon['amount'] += $item['order'][0]['payPrice'] ?: 0;
            }
        }
        return [
            'pageNum'   => $list->currentPage(),
            'pageSize'  => $list->perPage(),
            'pageCount' => ceil($list->total() / $list->perPage()),
            'count'     => $list->total(),
            'lists'     => $coupon,
        ];

    }

    /**
     * 用户购买券包发放优惠券
     * @param $packageId
     * @param $userId
     * @param $type
     * @param array $usedCoupon = ['couponId'=>"num"]
     * @param int $shopId
     * @param string $couponPackageOrderId
     * @return array
     * @throws CustomerCouponException
     */
    public static function buyCouponPackageSendCoupon(
        $packageId,
        $userId,
        $type,
        array $usedCoupon = [],
        int $shopId = 0,
        string $couponPackageOrderId = ''
    ): array {
        $uuid = md5(microtime(true) . rand(1, 10000));
        Log::info("{$uuid}-进入购买券包发放优惠券-{$userId}",
            ['userId' => $userId, 'packageId' => $packageId, 'shopId' => $shopId]);
        $insertCouponCollection = new Collection();
        $userCouponIds          = [];
        //根据券包id查询信息
        $packageInfo   = CouponPackageService::getCouponPackageInfoById($packageId);
        $activityBasis = $packageInfo->toArray();
        //活动基本信息
        //活动关联优惠券信息
        $couponMapping        = $activityBasis['coupon_package_mapping_rel'];//关联数量
        $couponMappingInfo    = $activityBasis['coupon_package_mapping_info_rel'];//优惠券详情
        $couponMappingKeyById = array_column($couponMapping, null, 'couponId');
        if (!empty($activityBasis) || empty($couponInfo)) {
            //活动店铺信息
            $shopInfo          = array_column($activityBasis['coupon_package_shop_mapping_rel'], null, 'shopId');
            $couponArr         = [];
            $customerCouponArr = [];
            try {
                DB::beginTransaction();
                foreach ($couponMappingInfo as $coupon) {
                    for ($i = 1; $i <= $couponMappingKeyById[$coupon['id']]['number']; $i++) {
                        $couponArr = [];
                        $couponArr['userId']         = $userId;
                        $couponArr['activityId']     = $packageId;
                        $couponArr['source']         = CustomerCouponModel::SOURCE_COUPON_PACKAGE;
                        $couponArr['sourceName']     = $activityBasis["name"] ?? "";
                        $couponArr['couponId']       = $coupon['id'];
                        $couponArr['couponCode']     = self::generateUserCouponCode(CodeEnum::COUPON_CODE_LENGTH);
                        $couponArr['name']           = $coupon['name'];
                        $couponArr['desc']           = $coupon['desc'];
                        $couponArr['couponType']     = $coupon['type'];
                        $couponArr['useTimeType']    = $coupon['useTimeType'];
                        $couponArr['canUseProduct']  = $coupon['canUseProduct'];
                        $couponArr['productUseType'] = $coupon['productUseType'];
                        $couponArr['shopType']       = $activityBasis['shopType'];
                        $couponArr['discount']       = $coupon['discount'];
                        $couponArr['couponImg']      = $coupon['couponImg'];
                        if (isset($usedCoupon[$coupon['id']]) && $usedCoupon[$coupon['id']] > 0) {
                            //如果有使用的优惠券并且数量大于0，添加时状态为已使用
                            $couponArr['status']    = CodeEnum::COUPON_STATUS_USED;
                            $couponArr['useTime']   = time();
                            $couponArr['useShopId'] = $shopId;
                        } else {
                            $couponArr['status'] = CodeEnum::COUPON_STATUS_NO_USED;
                        }
                        if ($coupon['useTimeType'] == CodeEnum::USE_TIME_TYPE_FIXED) {
                            //如果等于1 表示固定时间
                            $couponArr['startAt'] = $coupon['startAt'];
                            $couponArr['endAt']   = $coupon['endAt'];
                        } else {
                            //如果等于2 表示 领取后几天生效 有效期是几天
                            $startTime            = time() + $coupon['startAt'] * CodeEnum::COUPON_DAY_TIME;
                            $year                 = date("Y", $startTime);
                            $month                = date("m", $startTime);
                            $day                  = date("d", $startTime) + $coupon['endAt'];
                            $endTime              = mktime(23, 59, 59, $month, $day, $year);//当天结束时间戳
                            $couponArr['startAt'] = $startTime;
                            $couponArr['endAt']   = $endTime;
                        }
                        $couponArr['useCondition']        = $coupon['useCondition'];
                        $couponArr['useMax']              = $coupon['useMax'];
                        $couponArr['costPrice']           = $coupon['costPrice'];
                        $couponArr['availableSource']     = $coupon['availableSource'];
                        $couponArr['isSuperposeCoupon']   = $coupon['isSuperposeCoupon'];
                        $couponArr['isSuperposeActivity'] = $coupon['isSuperposeActivity'];
                        $couponArr['unableDate']          = $coupon['unableDate'];
                        $couponArr['unableTime']          = $coupon['unableTime'];
                        $couponArr['isWechatNotice']      = $activityBasis['isWechatNotify'] ?? 0;
                        $couponArr['isSmsNotice']         = $activityBasis['isSmsNotify'] ?? 0;
                        $couponArr['notifyAheadDays']     = $activityBasis['notifyAheadDays'] ?? 0;
                        $couponArr['cappedAmount']        = $coupon['cappedAmount'];
                        $couponArr['isExpireNotice']      = $coupon['isExpireNotice'];
                        $couponArr['isArrivalNotice']     = $coupon['isArrivalNotice'];
                        $couponArr['expireNoticeDay']     = $coupon['expireNoticeDay'];
                        $couponArr['createdAt']           = time();
                        Log::info("{$uuid}-购买券包发放优惠券：优惠券信息", $couponArr);
                        //优惠券信息入库
                        $customerCouponId = CustomerCouponModel::insertData($couponArr);
                        if (isset($usedCoupon[$coupon['id']]) && $usedCoupon[$coupon['id']] > 0) {
                            $usedCoupon[$coupon['id']]            -= 1;
                            $customerCouponArr[$customerCouponId] = $coupon['id'];
                        }
                        $customerCouponIdArr = ['customerCouponId' => $customerCouponId];
                        //如果是活动门店是部分门店，则需要加入关联表，其他不加入
                        if ($activityBasis['shopType'] == CodeEnum::COUPON_SHOP_TYPE_PART) {
                            array_walk($shopInfo, function (&$value, $key, $customerCouponIdArr) {
                                unset($value['couponPackageId']);
                                $value = array_merge($value, $customerCouponIdArr);
                            }, $customerCouponIdArr);
                            //绑定用户优惠券店铺
                            Log::info("{$uuid}-购买券包发放优惠券：店铺信息", $shopInfo);
                            CustomerCouponShopMappingModel::addData($shopInfo);
                        } else {
                            CustomerCouponShopMappingModel::addData(['shopId' => 0, 'customerCouponId' => $customerCouponId, 'createdAt' => time()]);
                        }

                        $insertCouponCollection->push((object)[
                            'name'            => $couponArr['name'],
                            'startAt'         => $couponArr['startAt'],
                            'endAt'           => $couponArr['endAt'],
                            'isExpireNotice'  => $couponArr['isExpireNotice'],
                            'isArrivalNotice' => $couponArr['isArrivalNotice'],
                            'expireNoticeDay' => $couponArr['expireNoticeDay']
                        ]);

                        array_push($userCouponIds, $customerCouponId);
                    }
                }
                //记录发放日志
                $data = [
                    'userId'       => $userId,
                    'activityId'   => $packageId,
                    'activityType' => $type,
                    'createdAt'    => time(),
                    'updatedAt'    => time(),
                ];
                CustomerSendCouponLogService::addData($data);
                DB::commit();
                //优惠券到账&到期提醒
                self::dispatchCouponMsg($userId, $insertCouponCollection, $shopId);
                // 【 队列入队 】【 领取优惠券 】
                try {
                    $extOrderExists = false;
                    if ($couponPackageOrderId && $shopId > 0) {
                        $extOrderExists = OrderExternalSplitModel::suffix($shopId)->query()
                                                                 ->where('extOrderId', $couponPackageOrderId)
                                                                 ->exists();
                    }
                    foreach ($userCouponIds as $k => $userCouponIdSingle) {
                        ReceiveCouponJob::dispatch(
                            $shopId,
                            $packageId,
                            ReceiveCouponJob::TYPE_COUPON_PACKAGE,
                            $couponPackageOrderId,
                            vsprintf('[ %s ] - [ %s ] - [ %s ]', [
                                $extOrderExists ? '随订单购买' : '直接购买',
                                '券包购买',
                                $packageInfo['name']
                            ]),
                            $userCouponIdSingle,
                            $k == 0 ? $userCouponIds : []
                        )->onQueue(ReceiveCouponJob::$QUEUE_NAME);
                    }
                } catch (\Exception $e) {
                    CommonService::fsLogException(
                        '【 队列入队 】【 领取优惠券 】', $e, [
                        'shopId'   => $shopId,
                        'source'   => '【 券包购买 】- ' . $activityBasis['name'],
                        'couponId' => $packageId
                    ], true);
                }

                Log::info("{$uuid}-购买券包发放优惠券：成功", ['userId' => $userId, 'packageId' => $packageId]);
                return $customerCouponArr;
            } catch (\Exception $exception) {
                DB::rollBack();
                Log::info("{$uuid}-购买券包发放优惠券：失败",
                    ['userId' => $userId, 'packageId' => $packageId, 'msg' => $exception->getMessage()]);
                //飞书告警
                SendFs::newRobot()->setTitleContent('购买券包发券失败',
                    "userId:{$userId}---couponPackageId:{$packageId}---message：{$exception->getMessage()}")->send();
                throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_CUSTOMER_COUPON_RECEIVED_FAIL);
            }
        } else {
            Log::info("{$uuid}-绑定手机号发放优惠券：失败",
                [
                    'userId'    => $userId,
                    'packageId' => $packageId,
                    'msg'       => CustomerCouponCodeEnum::ERR_CUSTOMERCOUPON_ID_NOT_EXIST
                ]);
            SendFs::newRobot()
                  ->setTitleContent('购买券包发券失败',
                      "userId:{$userId}---couponPackageId:{$packageId}---message:活动不存在或者信息错误")
                  ->send();
            throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_CUSTOMER_COUPON_RECEIVED_FAIL);
        }
    }

    /**
     * 获取优惠券详情
     *
     * @param int $id
     * @return array
     * @throws CustomerCouponException
     */
    public static function customerCouponDetail(int $id): array
    {
        try {
            $customerCoupon = CustomerCouponModel::query()
                                                 ->where("id", $id)
                                                 ->with([
                                                     "couponShopRel" => function ($query) {
                                                         $query->with("shopRel");
                                                     }
                                                 ])
                                                ->with([
                                                    'couponRel' => function ($query) {
                                                        return $query->select(['id', 'name','availableSource']);
                                                    }
                                                ])
                                                 ->first();
            if ($customerCoupon) {
                $customerCoupon->platformId = PlatformCodeEnum::PLATFORM_APPLET_WECHAT_APPLET;// 微信小程序
            }
            return [
                "couponDetail" => $customerCoupon ? CustomerCouponDetailResource::collection([$customerCoupon])
                                                                                ->getIterator()
                                                                                ->current() : new \stdClass()
            ];
        } catch (\Exception $exception) {
            throw new CustomerCouponException(
                CustomerCodeEnum::ERR_GET_CUSTOMER_COUPON_DETAIL,
                "获取优惠券详情失败",
                $exception
            );
        }
    }

    /**
     * 校验优惠券使用状态
     *
     * @param int $id
     * @param int $userId
     * @return int
     */
    public static function checkCouponStatus(int $id, int $userId): int
    {
        return Cache::remember(CustomerCouponCacheEnum::getUserCouponStatusKey($id), 600,
            function () use ($id, $userId) {
                return CustomerCouponModel::query()->where('id', $id)->where('userId', $userId)->select(['status'])
                                          ->value('status') ?? 0;
            });
    }

    public static function getCouponInfoByCode(string $code)
    {
        $info = CustomerCouponModel::query()
                                   ->where('couponCode', $code)
                                   ->with('couponShopRel')
                                   ->get()
                                   ->each(function ($item) {
                                       $inShopList = [];
                                       foreach ($item->couponShopRel as $couponShop) {
                                           $inShopList[] = $couponShop->shopId;
                                       }
                                       $item->inShopList = $inShopList;
                                   });
        return $info;

    }

    /**
     * 活动领券
     *
     * @param int $uid
     * @param int $shopId
     * @param int $activityId
     * @param int $platform
     * @return array
     * @throws BaseException
     * @throws CustomerCouponException
     * @throws InvalidArgumentException
     */
    public static function activityCouponReceive(int $uid, int $shopId, int $activityId, int $platform): array
    {
        try {
            $lockKey = CustomerCouponCacheEnum::getActivityReceiveCouponLock($uid, $activityId);
            if (!Redis::setnx($lockKey, time())) {
                $lock_time = Redis::get($lockKey);
                if (($lock_time + 5) < time()) {
                    Redis::del($lockKey);
                } else {
                    throw new CustomerCouponException(BaseCodeEnum::ERR_400000, '您的请求太频繁啦，请稍后再试~');
                }
            }

            if (!($activity = ActivityModel::checkShopActivityExists($activityId, $shopId))) {
                throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_SHOP_ACTIVITY);
            }

            if ($activity->limitJoinNum > 0 && $activity->limitJoinNum <= $activity->hasJoinNum) {
                throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_JOINED_GT_LIMIT_MAX);
            }

            if ($activity->endAt < time()) {
                throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_ACTIVITY_LOSE_EFFECTIVE);
            }

            if ($activity->status != ActivityEnum::STATUS_RUNNING) {
                throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_ACTIVITY_STATUS);
            }

            //判断是否有参与过当前活动
            if (ActivityModel::checkJoinActivity($uid, $activityId)) {
                throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_CUSTOMER_COUPON_HAS_RECEIVED);
            }

            switch ($activity->type){
                case ActivityEnum::TYPE_START_BUSINESS_ACTIVITY:
                    // todo 开业活动限制参与一次
                    if (ActivityModel::checkJoinShopTypeActivity($shopId, $uid, $activity->type)) {
                        throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_JOINED_SHOP_START_BUSINESS_ACTIVITY);
                    }
                    break;
                case ActivityEnum::TYPE_DAILY_ACTIVITY:
                    // todo 日常活动增加开业活动是否参与限制
                    if ($activity->isAttendOpenActivity) {
                        $isJoinBusinessActivity = CustomerSendCouponLogModel::query()
                                                                            ->where("userId", $uid)
                                                                            ->where("shopId", $shopId)
                                                                            ->where("activityType",
                                                                                ActivityEnum::TYPE_START_BUSINESS_ACTIVITY)
                                                                            ->count();
                        if($isJoinBusinessActivity){
                            throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_JOIN_BUSINESS_ACTIVITY);
                        }
                    }
                    break;
            }

            $userinfo = CustomerPlatformModel::query()
                                             ->where('userId', $uid)
                                             ->where('platformId', PlatformCodeEnum::PLATFORM_APPLET_WECHAT_APPLET)
                                             ->first();
            // 判断领券限制
            if ($activity->isAttendEd == BaseModel::SWITCH_ON) {
                $isFollow = CustomerPlatformModel::query()
                                                 ->where('unionid', $userinfo->unionid)
                                                 ->where('platformId', PlatformCodeEnum::PLATFORM_APPLET_OFFICIAL)
                                                 ->exists();

                if (!$isFollow) {
                    Log::channel('wechat')->info('The user did not follow the coupon：', [
                        'userId'  => $uid,
                        'unionid' => $userinfo->unionid,
                        'shopId'  => $shopId
                    ]);
                    throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_CUSTOMER_COUPON_RECEIVED_FAIL,
                        '抱歉，您还未关注「夸父炸串公司」公众号，请关注后再来领取');
                }
            }

            // 测试门店判断用户是否关注过公众号

            // TODO 到 2023 年 10 月 1日 月后 下面 这块代码可以删了
            $shopInfo      = ShopService::getShopInfo($shopId);
            $limitShopList = WechatConfigService::getLimitShopList();
            $keyLists      = array_keys($limitShopList);
            if (in_array($shopInfo['shopCode'], $keyLists)) {
                $userinfo = CustomerPlatformModel::query()
                                                 ->where('userId', $uid)
                                                 ->where('platformId', PlatformCodeEnum::PLATFORM_APPLET_WECHAT_APPLET)
                                                 ->first();

                $isFollow = CustomerPlatformModel::query()
                                                 ->where('unionid', $userinfo->unionid)
                                                 ->where('platformId', PlatformCodeEnum::PLATFORM_APPLET_OFFICIAL)
                                                 ->exists();

                if (!$isFollow) {
                    Log::channel('wechat')->info('The user did not follow the coupon：', [
                        'userId'  => $uid,
                        'unionid' => $userinfo->unionid,
                        'shopId'  => $shopId
                    ]);
                    throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_CUSTOMER_COUPON_RECEIVED_FAIL,
                        '抱歉，您还未关注「夸父炸串公司」公众号，请关注后再来领取');
                }
            }

            // TODO 几个月后 上面 这块代码可以删了


            $userCouponIds = CustomerCouponService::sendCoupon($uid, $activityId, $activity->type, $shopId);

            //删除用户缓存
            Redis::del(\App\Kuafu\Customer\Enum\CodeEnum::PREFIX_PLATFORM . $platform . ':' . \App\Kuafu\Customer\Enum\CodeEnum::PREFIX_USERID . $uid);
            Redis::del($lockKey);

            try {
                // 异步添加用户日志
                (new CustomerActionLogService())->asynSaveData([
                    'userId'   => $userinfo->userId,
                    'unionId'  => $userinfo->unionid,
                    'type'     => CustomerActionLogModel::ACTION_TYPE_GET_ACTIVITY_COUPON,
                    'userInfo' => [
                        'shopId'       => $shopId,
                        'activityId'   => $activityId,
                        'activityType' => $activity->type,
                        'openId'       => $userinfo->openId,
                    ]
                ]);
            } catch (\Exception $exception) {

            }

            return ["userCouponIds" => $userCouponIds];
        } catch (BaseException $baseException) {
            throw $baseException;
        } catch (\Exception $exception) {
            throw new CustomerCouponException(
                CustomerCouponCodeEnum::ERR_CUSTOMER_COUPON_RECEIVED_FAIL,
                "活动领券失败",
                $exception
            );
        }
    }

    /**
     * @param int $suitShopId
     * @param int $activityId
     * @param int $activityType
     * @param string $activityName
     * @param int $couponId
     * @param int $couponType
     * @param string $couponName
     * @param  $couponStatus
     * @param string $username
     * @param int $uid
     * @param string $mobile
     * @param string $receiveTimeStart
     * @param string $receiveTimeEnd
     * @param string $useTimeStart
     * @param string $useTimeEnd
     * @param int $page
     * @param int $pageSize
     * @return array
     */
    public static function lists(
        int $suitShopId,
        int $activityId,
        int $activityType,
        string $activityName,
        int $couponId,
        int $couponType,
        string $couponName,
        $couponStatus,
        string $username,
        int $uid,
        string $mobile,
        string $receiveTimeStart,
        string $receiveTimeEnd,
        string $useTimeStart,
        string $useTimeEnd,
        int $page,
        int $pageSize
    ): array {
        $queryBuilder = function ($query) use (
            $suitShopId,
            $activityId,
            $activityName,
            $activityType,
            $couponId,
            $couponType,
            $couponName,
            $couponStatus,
            $uid,
            $mobile,
            $username,
            $receiveTimeEnd,
            $receiveTimeStart,
            $useTimeStart,
            $useTimeEnd
        ) {
            $query->when($activityType > 0, function($query)use($activityType){
                $query->where("activityType", $activityType);
            })->when($activityId > 0, function($query)use($activityId){
                $query->where("activityId", $activityId);
            })->when(strlen($activityName) > 0, function($query)use($activityName){
                $query->where("activityName", $activityName);
            })->when(
                $uid > 0 || strlen($mobile) > 0 || strlen($username) > 0,
                function ($query) use ($mobile, $uid, $username) {
                    $query->whereIn(
                        "userId",
                        CustomerModel::query()
                                     ->when(
                                         $uid > 0,
                                         function ($query) use ($uid) {
                                             $query->where("id", $uid);
                                         })
                                     ->when(
                                         strlen($mobile) > 0,
                                         function ($query) use ($mobile) {
                                             $query->where("mobile", "like", "%{$mobile}%");
                                         })
                                     ->when(
                                         strlen($username) > 0,
                                         function ($query) use ($username) {
                                             $query->where("name", "like", "%{$username}%");
                                         })
                                     ->pluck("id")->toArray()
                    );

//                    $query->whereHas("customers", function ($query) use ($mobile, $uid, $username) {
//                        $query->when($uid > 0, function ($query) use ($uid) {
//                            $query->where("id", $uid);
//                        })->when(strlen($mobile) > 0, function ($query) use ($mobile) {
//                            $query->where("mobile", "like", "%{$mobile}%");
//                        })->when(strlen($username) > 0, function ($query) use ($username) {
//                            $query->where("name", "like", "%{$username}%");
//                        });
//                    });
                }
            )->when(
                $couponId > 0 || strlen($couponName) > 0 || $couponType > 0,
                function ($query) use ($couponId, $couponName, $couponType) {
                    $query
                        ->when($couponId > 0, function ($query) use ($couponId) {
                            $query->where("couponId", $couponId);
                        })->when(is_int($couponType) && $couponType > 0, function ($query) use ($couponType) {
                            $query->where("couponType", $couponType);
                        })->when(strlen($couponName) > 0, function ($query) use ($couponName) {
                            $query->where("name", "like", "%{$couponName}%");
                        });
                }
            )->when($suitShopId > 0, function ($query) use ($suitShopId) {
                $suitShopType = Shop::query()->where("id", $suitShopId)->first()->type;
                $query->where(function ($query) use ($suitShopId, $suitShopType) {
                    $query
                        ->whereIn('id', function ($q) use ($suitShopId) {
                            $q->select('customerCouponId')
                              ->from((new CustomerCouponShopMappingModel())->getTable())
                              ->whereIn('shopId', [$suitShopId, 0]);
                        })
//                        ->whereIn(
//                            "id",
//                            CustomerCouponShopMappingModel::query()
//                                                          ->where('shopId', $suitShopId)
//                                                          ->pluck("customerCouponId")
//                                                          ->toArray()
//                        )->orWhere(
//                            'shopType', '=', CouponPackageEnum::SHOP_TYPE_ALL
//                        )->orWhere('shopType', '=', $suitShopType);
                    ->whereIn('shopType', [CouponPackageEnum::SHOP_TYPE_ALL, CouponPackageEnum::SHOP_TYPE_SELECTION, $suitShopType]);
                });
            }
            )->when(strlen($receiveTimeStart) > 0,
                function ($query) use ($receiveTimeStart) {
                    $query->where("createdAt", ">", strtotime($receiveTimeStart));
                }
            )->when(strlen($receiveTimeEnd) > 0,
                function ($query) use ($receiveTimeEnd) {
                    $query->where("createdAt", "<", strtotime("+1 day", strtotime($receiveTimeEnd)));
                }
            )->when(strlen($useTimeStart) > 0,
                function ($query) use ($useTimeStart) {
                    $query->where("useTime", ">=", strtotime($useTimeStart));
                }
            )->when(strlen($useTimeEnd) > 0,
                function ($query) use ($useTimeEnd) {
                    $query->where("useTime", "<", strtotime("+1 day", strtotime($useTimeEnd)));
                }
            )->when(strlen($couponStatus) > 0, function ($query) use ($couponStatus) {
                switch ($couponStatus) {
                    case CustomCouponListResource::STATUS_STAY_FOR_USE:
                        $query->where("startAt", "<", time())->where("endAt", ">", time())
                              ->where("status", CodeEnum::COUPON_STATUS_NO_USED);
                        break;
                    case CustomCouponListResource::STATUS_STAY_EFFECTIVE:
                        $query->where("startAt", ">", time());
                        break;
                    case CustomCouponListResource::STATUS_UN_EFFECTIVE:
                        $query->where("endAt", "<", time())->where("status", CodeEnum::COUPON_STATUS_NO_USED);
                        break;
                    case CustomCouponListResource::STATUS_USED:
                        $query->where("status", CodeEnum::COUPON_STATUS_USED);
                        break;
                }
            });
        };

        $customCouponLists = CustomerCouponModel::query()
                                                ->with([
                                                        "customers",
                                                        "couponShopRel" => function (HasMany $query) {
                                                            $query->with("shopRel");
                                                        },
                                                        "activityRel"
                                                    ]
                                                )->where($queryBuilder)
                                                ->orderBy("id", "desc")
                                                ->paginate($pageSize, ['*'], 'page', $page);

        return [
            "count"            => $customCouponLists->total(),
            "list"             => CustomCouponListResource::collection($customCouponLists->items()),
            'pageNum'          => $page,
            'pageSize'         => $pageSize,
            "usedNum"          => CustomerCouponModel::query()
                                                     ->where($queryBuilder)
                                                     ->where("status", CodeEnum::COUPON_STATUS_USED)
                                                     ->count(),
            "stayUsedNum"      => CustomerCouponModel::query()
                                                     ->where($queryBuilder)
                                                     ->where("status", CodeEnum::COUPON_STATUS_NO_USED)
                                                     ->where("startAt", "<", time())->where("endAt", ">", time())
                                                     ->count(),
            "stayEffectiveNum" => CustomerCouponModel::query()
                                                     ->where($queryBuilder)
                                                     ->where("status", CodeEnum::COUPON_STATUS_NO_USED)
                                                     ->where("startAt", ">", time())
                                                     ->count(),
            "unEffectiveNum"   => CustomerCouponModel::query()
                                                     ->where($queryBuilder)
                                                     ->where("status", CodeEnum::COUPON_STATUS_NO_USED)
                                                     ->where("endAt", "<", time())
                                                     ->count()
        ];
    }


    /**
     * 门店优惠券 - 商家端核销列表
     *
     * @param int $page
     * @param int $pageSize
     * @param int $shopId
     * @param string $couponCode
     * @param int $operateTimeStart
     * @param int $operateTimeEnd
     * @return array|void
     * @throws BaseException
     */
    public static function usedList(
        int $page,
        int $pageSize,
        int $shopId,
        string $couponCode,
        int $operateTimeStart,
        int $operateTimeEnd,
        int $type,
        int $serialNum,
        string $couponTitle,
        string $orderId,
        int $couponFrom
    ) {
        try {
            $paginate = CustomerCouponUseHistoryModel::getShopCouponUseHistory(
                $page,
                $pageSize,
                $shopId,
                CustomerCouponModel::USE_TYPE_MERCHANT,
                $couponCode,
                $operateTimeStart,
                $operateTimeEnd,
                $type,
                $serialNum,
                $couponTitle,
                $orderId,
                $couponFrom
            );

            return [
                "page"     => $page,
                "pageSize" => $pageSize,
                "list"     => CustomCouponUseHistoryListResource::collection($paginate->items())
            ];

        } catch (\Exception $exception) {
            handleException($exception, "获取优惠券核销列表失败");
        }
    }


    /**
     * 商家段优惠券详情
     *
     * @param string $couponCode
     * @param int $shopId
     * @return array|void
     * @throws BaseException
     */
    public static function merchantCustomerCouponDetail(string $couponCode, int $shopId, bool $isFormat = false)
    {
        try {
            $customerCoupon = CustomerCouponModel::getCustomerCouponDetailByCouponCode($couponCode);
            $shopModel      = Shop::getShopDetailById($shopId);
            self::validateCoupon($shopModel, $customerCoupon);

            if ($isFormat) {
                $detail = CouponExtBase::formatPrepareResponseData(
                    1,
                    1,
                    '',
                    $customerCoupon->name,
                    $customerCoupon->couponCode,
                    $customerCoupon->couponType, // TODO 检查一下
                    0,
                    $customerCoupon->discount,
                    $customerCoupon->startAt,
                    $customerCoupon->endAt,
                    CouponExtEnum::EXT_PLATFORM_KUAFU
                );
            } else {
                $detail = CustomerCouponDetailResource::collection([$customerCoupon])->getIterator()->current();
            }
            return compact('detail');

        } catch (\Exception $exception) {
            handleException($exception, "获取优惠券详情失败");
        }
    }

    /**
     * 获取所有类型的券信息
     *
     * @param int $shopId
     * @param string $couponCode
     * @param int $couponType
     * @return array
     * @throws BaseException
     * @throws GuzzleException
     * @throws CouponExtException
     */
    public static function getAllTypeCoupon(int $shopId, string $couponCode, int $couponType): array
    {
        return Cache::remember('getAllTypeCoupon_' . $shopId . ':' . $couponCode . ':' . $couponType, 10,
            function () use ($shopId, $couponCode, $couponType) {
                switch ($couponType) {
                    case CouponExtEnum::EXT_PLATFORM_KUAFU:
                        $result = CustomerCouponService::merchantCustomerCouponDetail($couponCode, $shopId,
                            true)['detail'] ?? [];
                        break;
                    case CouponExtEnum::EXT_PLATFORM_MEITUAN:
                    case CouponExtEnum::EXT_PLATFORM_DOUYIN:
                        $model  = new OrderCouponExternalService($couponType, $shopId);
                        $result = $model->getCouponExtInfo($couponCode, true);
                        break;
                    default:
                        $result = [];
                }
                return $result;
            });
    }

    /**
     * @throws GuzzleException
     * @throws BaseException
     * @throws CouponExtException
     */
    public static function getAllTypeCouponWithVerify(
        int $shopId,
        string $couponCode,
        int $couponType,
        bool $needProductList = false
    ): array {
        $result = self::getAllTypeCoupon($shopId, $couponCode, $couponType);

        if ($couponType != CouponExtEnum::EXT_PLATFORM_KUAFU) {
            // 校验商品是否关联三方 ID
            if (empty($result['canUseProduct'])) {
                throw new CouponExtException(CouponExtCodeEnum::ERR_COUPON_PRODUCT_NOT_EXIST);
            }
        }

        if ($needProductList) {
            $orderProductDetail    = ProductService::getProductInfoById($result['canUseProduct']);
            $result['productList'] = $orderProductDetail['productList'] ?? [];
            unset($result['dealMenu']);
        }

        return $result;
    }


    /**
     * 校验优惠券
     *
     * @param Shop $shopModel
     * @param CustomerCouponModel|null $customerCouponModel
     * @throws CustomerCouponException
     */
    public static function validateCoupon(Shop $shopModel, CustomerCouponModel $customerCouponModel = null)
    {
        if (!$customerCouponModel || $customerCouponModel->status != CodeEnum::COUPON_STATUS_NO_USED) {
            throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_CUSTOMER_COUPON_NOT_EXISTS);
        }

        if ($customerCouponModel->shopType == CouponPackageEnum::SHOP_TYPE_SELECTION) {
            if (
                !$customerCouponModel->couponShopRel
                ||
                $customerCouponModel->couponShopRel->where("shopId", $shopModel->id)->count() == 0
            ) {
                throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_SHOP_CUSTOMER_COUPON);
            }
        } else {
            if ($customerCouponModel->shopType != CouponPackageEnum::SHOP_TYPE_ALL && $customerCouponModel->shopType != $shopModel->type) {
                throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_SHOP_CUSTOMER_COUPON);
            }
        }

        if (!($customerCouponModel->startAt < time() && $customerCouponModel->endAt > time())) {
            throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_CUSTOMER_NOT_CAN_USE);
        }
    }

    /**
     * 商家端核销优惠券
     *
     * @param string $couponCode
     * @param int $shopId
     * @throws BaseException
     */
    public static function use(string $couponCode, int $shopId)
    {
        try {
            $customerCoupon    = CustomerCouponModel::getCustomerCouponDetailByCouponCode($couponCode);
            $customerCouponOrg = clone $customerCoupon;
            $shopModel         = Shop::getShopDetailById($shopId);
            self::validateCoupon($shopModel, $customerCoupon);

            CustomerCouponUseHistoryModel::record(
                $customerCoupon,
                CustomerCouponUseHistoryModel::TYPE_USE,
                $shopId,
                AuthService::getAuthUser()["id"] ?? 0,
                CustomerCouponModel::USE_TYPE_MERCHANT,
                0,
                $customerCouponOrg->name,
                $customerCouponOrg->couponType
            );

            $customerCoupon->setRawAttributes([
                "useTime"   => time(),
                "useType"   => CustomerCouponModel::USE_TYPE_MERCHANT,
                "useShopId" => $shopId,
                "status"    => CodeEnum::COUPON_STATUS_USED
            ]);
            $customerCoupon->save();

            Cache::forget(CustomerCouponCacheEnum::getUserCouponStatusKey($customerCouponOrg->id));
            // 异步添加用户日志

            (new CustomerActionLogService())
                ->setUnionIdByUserId($customerCouponOrg->userId)
                ->asynSaveData([
                    'userId'   => $customerCouponOrg->userId,
                    'type'     => CustomerActionLogModel::ACTION_TYPE_MERCHANT_USE_ACTIVITY_COUPON,
                    'userInfo' => [
                        'shopId'     => $shopId,
                        'couponCode' => $couponCode,
                        'couponId'   => $customerCouponOrg->couponId ?? '',
                        'activityId' => $customerCouponOrg->activityId ?? ''
                    ]
                ]);

        } catch (\Exception $exception) {
            handleException($exception, "核销优惠券失败");
        }
    }

    public static function verifyCode(array $orderInfo)
    {
        try {
            $couponList = $orderInfo['extCouponList'];
            foreach ($couponList as $item) {
                CustomerCouponUseHistoryModel::recordHistory(
                    $item['orderId'],
                    $orderInfo['serialNum'],
                    $item['couponExtCode'],
                    $item['couponExtName'],
                    $item['extPlatform'],
                    $item['couponExtType'], // 这是 三方券的类型 ，kf 的券类型需要转换成这个
                    $item['couponExtCostPrice'], // 券码实收
                    $item['couponExtDiscountPrice'], // 券码优惠
                    CustomerCouponUseHistoryModel::TYPE_USE,
                    $orderInfo['shopId'],
                    AuthService::getUserInfo('id', false),
                    AuthService::getUserInfo('username', false),
                    CustomerCouponModel::USE_TYPE_MERCHANT
                );
            }
        } catch (\Exception $exception) {
            handleException($exception, "核销优惠券失败");
        }
    }

    /**
     * 撤销优惠券
     *
     * @param string $couponCode
     * @param int $shopId
     * @throws BaseException
     */
    public static function cancelUse(string $couponCode, int $shopId)
    {
        try {
            $customerCouponModel = CustomerCouponModel::getCustomerCouponDetailByCouponCode($couponCode);
            $customerCouponOrg   = clone $customerCouponModel;

            if ($customerCouponModel->useShopId != $shopId) {
                throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_CUSTOMER_COUPON_NOT_EXISTS);
            }

            if (!($customerCouponModel->startAt < time() && $customerCouponModel->endAt > time())) {
                throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_CANCEL_CUSTOMER_COUPON_TIME);
            }

            CustomerCouponUseHistoryModel::record(
                $customerCouponModel,
                CustomerCouponUseHistoryModel::TYPE_CANCEL,
                $shopId,
                AuthService::getAuthUser()["id"] ?? 0,
                CustomerCouponModel::USE_TYPE_MERCHANT,
                0,
                $customerCouponOrg->name,
                $customerCouponOrg->couponType
            );

            $customerCouponModel->setRawAttributes([
                "useTime"   => 0,
                "useType"   => 0,
                "useShopId" => 0,
                "status"    => CodeEnum::COUPON_STATUS_NO_USED
            ]);
            $customerCouponModel->save();

            Cache::forget(CustomerCouponCacheEnum::getUserCouponStatusKey($customerCouponOrg->id));

        } catch (\Exception $exception) {
            handleException($exception, "撤销优惠券失败");
        }
    }

    /**
     * 撤销优惠券
     *
     * @param string $couponCode
     * @param int $shopId
     * @throws BaseException
     */
    public static function cancelExtUsedCoupon(string $couponCode, int $shopId)
    {
        try {
            $firstRow = CustomerCouponUseHistoryModel::query()
                                                     ->where('couponCode', $couponCode)
                                                     ->where('shopId', $shopId)
                                                     ->first();

            CustomerCouponUseHistoryModel::recordHistory(
                $firstRow['orderId'],
                $firstRow['serialNum'],
                $firstRow['couponCode'],
                $firstRow['couponTitle'],
                $firstRow['couponFrom'],
                $firstRow['couponType'], // 这是 三方券的类型 ，kf 的券类型需要转换成这个
                $firstRow['couponCostPrice'], // 券码实收
                $firstRow['couponExtDiscountPrice'], // 券码优惠
                CustomerCouponUseHistoryModel::TYPE_CANCEL,
                $firstRow['shopId'],
                AuthService::getUserInfo('id', false) ?: 0,
                AuthService::getUserInfo('username', false),
                CustomerCouponModel::USE_TYPE_MERCHANT
            );

        } catch (\Exception $exception) {

        }
    }

    /**
     * 获取订单可用优惠券列表
     * @param string $openId
     * @param string $poiId
     * @param int $pageNum
     * @param int $pageSize
     * @return array
     * @throws CustomerCouponException
     * @throws GuzzleException
     */
    public static function getUserCouponListFromDy(string $openId, string $poiId, int $pageNum, int $pageSize): array
    {
        try {
            $userCouponList = (new DouyinSelfService)->getUserCertificatesList($openId, $poiId, $pageNum, $pageSize);
        } catch (\Exception $e) {
            Log::info('getUserCouponListFromDy Err:', [
                'openId'   => $openId,
                'poiId'    => $poiId,
                'pageNum'  => $pageNum,
                'pageSize' => $pageSize,
                'msg'      => $e->getMessage(),
            ]);
            throw new CustomerCouponException(CustomerCouponCodeEnum::ERR_GET_DY_COUPON_FAIL);
        }

        if ($userCouponList && isset($userCouponList['orders']) && is_array($userCouponList['orders'])) {
                $thirdSkuIds = [];
                foreach ($userCouponList['orders'] as &$orders) {
                    $canUse = $orders['can_use'] ?? false;
                    if (!$canUse) {
                        continue;
                    }
                    if (isset($orders['certificates']) && count($orders['certificates'])) {
                        foreach ($orders['certificates'] as $certificates) {
                            $thirdSkuId = $certificates['sku_info']['third_sku_id'] ?? 0;
                            if ($thirdSkuId) {
                                $thirdSkuIds[] = $thirdSkuId;
                            }
                        }
                    }
                }

                if ($thirdSkuIds) {// 查询在数据库中菜品信息
                    $isExistProductIds = [];
                    Product::query()->whereIn("id", $thirdSkuIds)
                           ->where('menuId', 0)
                           ->select(['id'])
                           ->get()
                           ->map(function ($item) use (&$isExistProductIds) {
                               $isExistProductIds[] = $item->id;
                           });

                    if ($isExistProductIds) {
                        foreach ($userCouponList['orders'] as &$orders) {
                            $canUse = $orders['can_use'] ?? false;
                            if (!$canUse) {
                                continue;
                            }
                            if (isset($orders['certificates']) && count($orders['certificates'])) {
                                foreach ($orders['certificates'] as &$certificates) {
                                    $thirdSkuId = $certificates['sku_info']['third_sku_id'] ?? 0;
                                    if ($thirdSkuId && in_array($thirdSkuId, $isExistProductIds)) {
                                        $certificates['isExistProduct'] = true;
                                    } else {
                                        $certificates['isExistProduct'] = false;
                                    }
                                }
                            }
                        }
                    }
                }
            }

        return $userCouponList;
    }
}
